(function ($) {
    $.fn.extend({
        //  封装jquery的弹出式菜单
        'ejectAside': function (options, param) {
            const defaultOptions = {
                backgroundColor: 'black',
                menuSplitSize: 3,
                labelWidth: 136,
                color: 'black',
                url: '',
                method: 'GET',
                childItemNumberPerCol: 6,
                childItemNumberPerColField: 'childItemNumberPerCol',
                data: [],
                queryParams: {},
                idField: 'id',
                textField: 'text',
                iconCls: 'iconCls',
                childrenField: 'children',
                otherObjectField: 'attribute',
                width: '100%',
                height: '100%',
                filling: true,
            };
            const events = {
                onLoadSuccess: function (data) {
                },
                onLoadError: function (data) {
                },
                onBeforeLoad: function (param) {
                },
                onBeforeDestroy: function () {
                },
                onClickChild: function (id, node) {
                },
                onDblClickChild: function (id, node) {
                },
                onContextmenuChild: function (id, node, e) {
                },
                onLoadFilter: function (data) {
                    return data || [];
                }
            }
            const methods = {
                getOptions: function (jq) {
                    return $(jq).data('options');
                },
                select: function (jq, id) {
                    $(jq).find('li[key]').each(function (index, item) {
                        if ($(item).attr('key') == id) {
                            $(item).click();
                        }
                    })
                },
                destroy: function (jq) {
                    let opts = $(jq).data('options');
                    opts.onBeforeDestroy();
                    $(jq).remove();
                },
                loadData: function (jq, data) {
                    let opts = $(jq).data('options');
                    let backgroundColor = opts.backgroundColor || 'black';
                    $(jq).append(`<ul class="eject-aside-root"></ul>`);
                    $(jq).css('backgroundColor', backgroundColor);
                    for (let i = 0; i < data.length; i++) {
                        let childObject = data[i];
                        let child = `<li key="${childObject[opts['idField']]}">
                                         <div class="eject-aside-root-button" style="background-color: ${backgroundColor}; width: ${opts.width}${opts.width.indexOf('%') ? '' : 'px'};">
                                                <span class="eject-aside-icon-span ${childObject[opts['iconCls']]}"></span>
                                                <span class="eject-aside-root-button-text">
                                                        ${childObject[opts['textField']]}
                                                </span>
                                                <span class="eject-aside-icon-arrow_right"></span>
                                         </div>
                                     </li>`;
                        $(jq).find('.eject-aside-root').append(child);
                        let attr = {
                            id: childObject[opts['idField']],
                            text: childObject[opts['textField']],
                            attribute: childObject[opts['otherObjectField']]
                        }
                        $(jq).find('.eject-aside-root>li').eq(i).data('options', attr);
                        //  写入下级菜单
                        let children = childObject[opts['childrenField']] || [];
                        let childItemNumberPerCol = !isNaN(opts.childItemNumberPerCol) && opts.childItemNumberPerCol > 0 ? opts.childItemNumberPerCol : 6;
                        let localChildItemNumberPerCol = childObject[opts['childItemNumberPerColField']];
                        if (localChildItemNumberPerCol && !isNaN(localChildItemNumberPerCol)) {
                            childItemNumberPerCol = childObject[opts['childItemNumberPerColField']];
                        }
                        if (children.length > 0) {
                            let groupSize = Math.ceil(children.length / childItemNumberPerCol);
                            let labelWidth = opts.labelWidth || 136;
                            let div = $(`<div style="width: ${labelWidth * groupSize}px;background-color: ${backgroundColor}" id="ejectAsideWindowId_${childObject[opts['idField']]}" class="eject-aside-window"></div>`);
                            let childrenGroup = groupBy(children, childItemNumberPerCol);
                            for (let ind = 0; ind < childrenGroup.length; ind++) {
                                let ul = $('<ul></ul>');
                                for (let i of childrenGroup[ind]) {
                                    let attr = {
                                        key: i[opts['idField']],
                                        text: i[opts['textField']],
                                        attribute: i[opts['otherObjectField']]
                                    }
                                    let li = $(`<li key="${i[opts['idField']]}" 
                                                title="${i[opts['textField']]}">
                                               <span>${i[opts['textField']]}</span>
                                              </li>`);
                                    li.data('options', attr);
                                    ul.append(li);
                                }
                                if (opts.filling) {
                                    //  是否填充剩余项目
                                    for (let i = 0, len = opts.childItemNumberPerCol - childrenGroup[ind].length; i < len; i++) {
                                        let li = $(`<li title=""><span></span></li>`);
                                        li.data('options', attr);
                                        ul.append(li);
                                    }
                                }
                                div.append(ul);
                            }
                            $('body').append(div);
                        }
                    }
                    //  绑定鼠标移入事件
                    $('div[id*="ejectAsideWindowId_"]').on('mouseover', function () {
                        $(this).finish().css('display', 'block');
                        let key = $(this).attr('id').split('_');
                        key.splice(0, 1);
                        $('.eject-aside-root').find(`li[key=${key.join("")}]`).addClass('eject-aside-root-button-hovered');
                    })
                    //  绑定鼠标移出事件
                    $('div[id*="ejectAsideWindowId_"]').on('mouseout', function () {
                        $(this).fadeOut(200);
                        let key = $(this).attr('id').split('_');
                        key.splice(0, 1);
                        $('.eject-aside-root').find(`li[key=${key.join("")}]`).removeClass('eject-aside-root-button-hovered');
                    })
                    //  绑定弹出菜单事件
                    $('.eject-aside-root>li').hover(function () {
                        let options = $(this).data('options');
                        let windowId = `#ejectAsideWindowId_${options.id}`;
                        if ($(windowId).length <= 0) return;
                        let top = $(this).offset().top;
                        let left = $(this).offset().left;
                        let width = $(this).outerWidth(true);
                        let windowLeft = left + width + opts.menuSplitSize;
                        let windowHeight = $(windowId).outerHeight(true);
                        let windowWidth = $(windowId).outerWidth(true);
                        let documentHeight = $(document).outerHeight(true); // 768 这是测试机的高度
                        let documentWidth = $(document).outerWidth(true);
                        if (top + windowHeight > documentHeight) {
                            top = documentHeight - windowHeight - 5;
                        }
                        if (windowLeft + windowWidth > documentWidth) {
                            windowLeft = documentWidth - windowWidth - 5;
                        }
                        $(windowId).css({
                            top: top,
                            left: windowLeft
                        });
                        $(windowId).finish().fadeIn(300);
                    }, function () {
                        let options = $(this).data('options');
                        let windowId = `#ejectAsideWindowId_${options.id}`;
                        if ($(windowId).length <= 0) return;
                        $(windowId).fadeOut(200);
                    })
                }
            }
            if (typeof options === "object") {
                $(this).addClass('eject-aside-layout');
                //  添加背景颜色样式样式
                let p = $.extend({}, defaultOptions, events, options);
                $(this).css({width: p.width, height: p.height});
                $(this).data('options', p);
                p.onBeforeLoad.call(this, options);
                let o = this;
                if (p.url) {
                    loadRemoteData(p.url, p.queryParams, p.method, function (data) {
                        data = p.onLoadFilter.call(o, data);
                        methods.loadData(o, data);
                        p.onLoadSuccess.call(o, data);
                        bindEvents(o, p);
                    }, function (e) {
                        p.onLoadError.call(o, e);
                    }, {});
                } else {
                    p.data = p.onLoadFilter.call(o, p.data);
                    methods.loadData(this, p.data);
                    p.onLoadSuccess.call(this, p.onLoadFilter.call(o, p.data));
                    bindEvents(o, p);
                }
            } else if (typeof options == "string") {
                let fn = methods[options];
                if (fn == undefined) throw new Error("没有" + options + "方法!");
                fn(this, param);
            }

            /**
             * 绑定节点事件
             * @param o 调用方
             * @param p 当前属性
             */
            function bindEvents(o, p) {
                $(document).on('click', 'div[id*="ejectAsideWindowId_"] li[key]', function () {
                    let key = $(this).attr('key');
                    p.onClickChild.call(o, key, $(this));
                })
                $(document).on('dblclick', 'div[id*="ejectAsideWindowId_"] li[key]', function () {
                    let key = $(this).attr('key');
                    p.onDblClickChild.call(o, key, $(this));
                })
                $(document).on('contextmenu', 'div[id*="ejectAsideWindowId_"] li[key]', function (e) {
                    let key = $(this).attr('key');
                    p.onContextmenuChild.call(o, key, $(this), e);
                })
            }

            /**
             * 数组分组
             * @param arr   数组
             * @param size  长度
             * @returns {[]}
             */
            function groupBy(arr = [], size = 6) {
                if (size <= 0) size = 6;
                let newArr = [];
                if (arr.length <= 0) return newArr;
                let count = Math.floor(arr.length / size);
                for (let i = 0; i < count; i++) {
                    let a = [];
                    for (let j = 0; j < size; j++) {
                        a.push(arr[i * size + j]);
                    }
                    newArr.push(a);
                }
                if (count * size < arr.length) {
                    let sign = count * size;
                    let a = [];
                    for (let i = sign; i < arr.length; i++) {
                        a.push(arr[i]);
                    }
                    newArr.push(a);
                }
                return newArr;
            }

            /**
             * 加载远程数据
             * @param url       url
             * @param param     参数
             * @param method    请求方法
             * @param success   成功回调
             * @param error     失败回调
             * @param ajaxOptions   ajax其他参数
             * @returns {{getAllResponseHeaders: (function(): *), abort: (function(*=): *), setRequestHeader: (function(*=, *): *), readyState: number, getResponseHeader: (function(*): *), overrideMimeType: (function(*): *), statusCode: (function(*=): y)}|*}
             */
            function loadRemoteData(url, param, method, success, error, ajaxOptions) {
                let options = {
                    url: url,
                    data: param,
                    type: method,
                    dataType: 'json',
                    success: success,
                    error: error
                }
                return $.ajax($.extend({}, ajaxOptions, options));
            }
        }
    })
})(jQuery)